package com.asa.common.viewmodel

import android.accounts.NetworkErrorException
import androidx.lifecycle.viewModelScope
import com.asa.base.BaseApplication
import com.asa.base.BaseViewModel
import com.asa.common.net.NetModel
import com.asa.common.net.RequestConstant
import com.asa.common.net.Result
import kotlinx.coroutines.*
import org.json.JSONObject
import java.lang.Exception
import java.net.SocketTimeoutException

abstract class BaseNetViewModel<M: NetModel>:BaseViewModel() {


    protected val netModel : M by lazy { createNetModel() }

    abstract fun createNetModel():M

    open fun delayInvoke(function:()->Unit,timeMills:Long = 5000):Job{
        return runOnIO {
            delay(timeMills)
            function.invoke()
        }
    }

    open fun runOnIO(block:suspend ()->Unit):Job{
        return viewModelScope.launch(Dispatchers.IO){
            block.invoke()
        }
    }

    open fun runOnMain(block:()->Unit){
        viewModelScope.launch(Dispatchers.Main){
            block.invoke()
        }
    }


    open suspend fun withContextIO(block: suspend () -> Unit){
        withContext(Dispatchers.IO){
            block.invoke()
        }
    }

    open suspend fun withContextMain(block: suspend () -> Unit){
        withContext(Dispatchers.Main){
            block.invoke()
        }
    }


    open fun <T:Any> executeRequest(
        call:suspend ()->Result<T>,
        success:((data:T)->Unit)? = null,
        serviceError:((code:Int,msg:String)->Unit)? = null,
        netError:((code:Int,exce:Exception)->Unit)?=null
    ){
        try {
            runOnIO {
                val result = call.invoke()
                when(result){
                    is Result.Success->{
                        withContextMain {
                            success?.invoke(result.data)
                        }
                    }
                    is Result.SuccessNull->{
                        withContextMain {
                            success?.invoke(JSONObject() as T)
                        }
                    }
                    is Result.NetError->{

                        val exception = result.exception
                        if (exception is SocketTimeoutException || exception is RuntimeException || exception is retrofit2.HttpException) {
                            withContextMain {
                                netError?.invoke(
                                    RequestConstant.REQUEST_CODE_NETWORK_TIMEOUT,
                                    NetworkErrorException("network timeout")
                                )
                            }
                        }else{
                            withContextMain{netError?.invoke(RequestConstant.REQUEST_CODE_UNKNOWN_ERROR,result.exception)}
                        }
                    }
                    is Result.ServiceError->{
                        withContextMain {
                            serviceError?.invoke(result.code, result.msg)
                            // token为空时重试 todo
//                            if (result.code == 1009 || result.code == 1010 || result.code == 1011) {
//                            }
                        }
                    }
                }
            }


        }catch (exce:Exception){
            exce.printStackTrace()
        }
    }

}